/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.module.datalogging.web.controller;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.api.context.Context;
import org.openmrs.module.datalogging.configuration.Event;
import org.openmrs.module.datalogging.configuration.Variable;
import org.openmrs.module.datalogging.enums.EventType;
import org.openmrs.module.datalogging.filter.Filter;
import org.openmrs.module.datalogging.filter.FilterFactory;
import org.openmrs.module.datalogging.filter.FilterUtils;
import org.openmrs.module.datalogging.handler.event.EventHandler;
import org.openmrs.module.datalogging.handler.event.EventHandlerFactory;
import org.openmrs.module.datalogging.service.DataLoggingService;
import org.openmrs.module.datalogging.web.model.EventModel;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

@Controller
@RequestMapping("/module/datalogging/eventForm")
public class EventFormController {
	
	private static final Log log = LogFactory.getLog(VariableFormController.class);
	
	@RequestMapping(method = RequestMethod.GET)
	public void preparePage(@RequestParam(required = false, value = "eventId") Integer id, ModelMap map) {
		if (Context.isAuthenticated()) {
			DataLoggingService service = Context.getService(DataLoggingService.class);
			
			EventModel eventModel = new EventModel();
			if (id != null) {
				try {
					Event event = service.getEvent(id);
					BeanUtils.copyProperties(eventModel, event);
					
					EventHandler eventHandler = EventHandlerFactory.getHandler(event.getEventType());
					String[] filterExpressions = StringUtils.split(event.getEventFilter(), FilterUtils.EXPRESSION_SEPARATOR);
					
					for (String filterExpression : filterExpressions) {
						String filterKey = filterExpression.substring(0, filterExpression.indexOf(FilterUtils.KEY_SEPARATOR));
						String filterValue = filterExpression.substring(filterExpression.indexOf(FilterUtils.KEY_SEPARATOR) + 1);
						
						// special handling for rule because the LogicService as of now doesn't implements OpenmrsService yet
						// every element is just string
						// TODO: hack for rule type
						if (filterKey.equalsIgnoreCase(FilterUtils.RULE_STRING)) {
							BeanUtils.setProperty(eventModel, filterKey, filterValue);
							map.addAttribute(filterKey, StringUtils.split(filterValue, FilterUtils.VALUE_SEPARATOR));
						} else {
							if (eventHandler.supportFilter(filterKey)) {
								BeanUtils.setProperty(eventModel, filterKey, filterValue);
								
								Filter filterHandler = FilterFactory.getHandler(filterKey);
								Set<Object> objects = new HashSet<Object>();
								String[] filterValues = StringUtils.split(filterValue, FilterUtils.VALUE_SEPARATOR);
								for (String value : filterValues) {
									Object object = filterHandler.getFilterValue(value);
									if (object != null)
										objects.add(object);
								}
								map.addAttribute(filterKey, objects);
							}
						}
					}
					
					// putting the variable in the model
					Set<String> variables = new HashSet<String>();
					for (Variable variable : event.getVariables())
						variables.add(String.valueOf(variable.getVariableId()));
					eventModel.setVariable(StringUtils.join(variables, FilterUtils.VALUE_SEPARATOR));
					map.addAttribute("variables", event.getVariables());
				} catch (Exception e) {
					log.error("Error creating command object for the controller ...", e);
				}
			}
			
			map.addAttribute("event", eventModel);
			map.addAttribute("events", EventType.values());
		}
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public String process(@ModelAttribute("event") EventModel eventModel) throws Exception {
		DataLoggingService service = Context.getService(DataLoggingService.class);
		if (Context.isAuthenticated()) {
			
			Event event = new Event();
			if (eventModel.getEventId() != null)
				event = service.getEvent(eventModel.getEventId());
			
			BeanUtils.copyProperties(event, eventModel);
			
			Set<String> filterExpression = new HashSet<String>();
			EventHandler eventHandler = EventHandlerFactory.getHandler(event.getEventType());
			for (String supportedFilter : eventHandler.getSupportedFilters()) {
				String filterValue = BeanUtils.getProperty(eventModel, supportedFilter);
				if (StringUtils.isNotBlank(filterValue))
					filterExpression.add(StringUtils.join(Arrays.asList(supportedFilter, filterValue),
					    FilterUtils.KEY_SEPARATOR));
			}
			event.setEventFilter(StringUtils.join(filterExpression, FilterUtils.EXPRESSION_SEPARATOR));
			
			Set<Variable> variables = new HashSet<Variable>();
			for (String variableId : StringUtils.split(eventModel.getVariable(), FilterUtils.VALUE_SEPARATOR)) {
				Variable variable = service.getComponent(NumberUtils.toInt(variableId));
				if (variable != null)
					variables.add(variable);
			}
			event.setVariables(variables);
			service.saveEvent(event);
		}
		return "redirect:eventList.list";
	}
	
}
